package com.geqian.web.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.geqian.cache.cache.SimpleCacheTemplate;
import com.geqian.common.common.PageRequest;
import com.geqian.common.common.PageResult;
import com.geqian.common.common.ResponseResult;
import com.geqian.common.utils.AssertUtils;
import com.geqian.common.utils.UUIDUtils;
import com.geqian.file.storage.FileStorageTemplate;
import com.geqian.web.annotation.CustomTransaction;
import com.geqian.web.authentication.LoginUserDetails;
import com.geqian.web.common.dto.LoginDTO;
import com.geqian.web.common.dto.RegisterDTO;
import com.geqian.web.common.dto.RoleDto;
import com.geqian.web.common.vo.VerificationCodeVo;
import com.geqian.web.entity.Role;
import com.geqian.web.entity.User;
import com.geqian.web.entity.UserRole;
import com.geqian.web.mapper.RoleMapper;
import com.geqian.web.mapper.UserMapper;
import com.geqian.web.mapper.UserRoleMapper;
import com.geqian.web.pojo.Location;
import com.geqian.web.service.UserService;
import com.geqian.web.utils.IpUtils;
import com.geqian.web.utils.JwtUtils;
import com.geqian.web.utils.PageUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private SimpleCacheTemplate<String, Object> simpleCacheTemplate;

    @Resource
    private FileStorageTemplate storageTemplate;


    @Resource
    private UserRoleMapper userRoleMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private PasswordEncoder passwordEncoder;


    /**
     * 登录
     *
     * @param loginDTO
     * @return
     */
    @Override
    public ResponseResult<Object> login(LoginDTO loginDTO) {
        String flagKey = loginDTO.getFlagKey();
        String code = flagKey != null ? (String) simpleCacheTemplate.get(flagKey) : null;
        if (code == null) {
            return ResponseResult.fail("验证码已过期");
        }
        if (!Objects.equals(loginDTO.getVerificationCode(), code)) {
            return ResponseResult.fail("验证码错误");
        }
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginDTO.getUserName(), loginDTO.getPassword());
        //进行用户验证，调用UserDetailsServiceImpl中的loadUserByUsername方法验证用户信息
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        // authenticate 不为 null 认证通过，为 null 认证没通过
        if (Objects.isNull(authenticate)) {
            return ResponseResult.fail("用户名或密码错误");
        }
        //验证通过，从authenticate中获取用户信息
        LoginUserDetails loginUserDetails = (LoginUserDetails) authenticate.getPrincipal();

        //获取用户id
        String userId = loginUserDetails.getUser().getUserId().toString();

        User userEntity = this.baseMapper.selectById(userId);
        //判断用户是否停用
        if (Objects.equals(userEntity.getStatus(), "1")) {
            return ResponseResult.fail("用户状态异常，请联系管理员!!!");
        }

        Map<String, Object> payload = new HashMap<>();
        payload.put("userId", userId);
        payload.put("userName", loginDTO.getUserName());
        String jwt = JwtUtils.generateToken(payload);
        Map<String, String> data = new HashMap<>();
        data.put("token", jwt);
        simpleCacheTemplate.set("user:" + userId, loginUserDetails);
        return ResponseResult.success(data);
    }


    /**
     * 退出登录
     */
    @Override
    public ResponseResult<String> logout() {
        //获取 SecurityContextHolder 中的用户id
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUserDetails loginUserDetails = (LoginUserDetails) authentication.getPrincipal();
        String userId = loginUserDetails.getUser().getUserId().toString();
        //删除redis用户缓存
        simpleCacheTemplate.delete("user:" + userId);
        return ResponseResult.success("注销成功");
    }

    @Override
    public PageResult<User> pageSearch(PageRequest pageRequest) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        String key = pageRequest.getKey();
        if (AssertUtils.isNotEmpty(key)) {
            wrapper.like(User::getNickName, key);
        }
        PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
        List<User> userList = this.baseMapper.selectList(wrapper);
        PageInfo<User> pageInfo = new PageInfo<>(userList);
        for (User user : pageInfo.getList()) {
            List<Role> roleList = roleMapper.selectUserRole(user.getUserId());
            if (!CollectionUtils.isEmpty(roleList)) {
                user.setRoleIdList(roleList.stream().map(Role::getRoleId).collect(Collectors.toList()));
                user.setRoleNameList(roleList.stream().map(Role::getRoleName).collect(Collectors.toList()));
            }
        }
        return PageUtils.getPageResult(pageInfo);
    }

    @Override
    public ResponseResult<User> userInfo(String token) {
        String userId = JwtUtils.parseForValue(token, "userId", String.class);
        User user = baseMapper.selectById(userId);
        List<Role> roleList = roleMapper.selectUserRole(Long.valueOf(userId));
        user.setRoleNameList(roleList.stream().map(Role::getRoleName).collect(Collectors.toList()));
        return ResponseResult.success(user);
    }

    @CustomTransaction
    @Override
    public ResponseResult<Object> deleteUser(Long userId) {
        User user = this.getById(userId);
        if (Objects.equals(user.getUserName(), "admin")) {
            return ResponseResult.fail("无法删除超级管理员");
        }
        this.baseMapper.deleteById(userId);

        if (Objects.nonNull(user.getAvatar())) {
            //删除阿里云oss存储图片
            storageTemplate.deleteFile(user.getAvatar().replaceFirst("^.*//.*aliyuncs.com/", "").replaceFirst("\\?.*", ""));
        }

        LambdaQueryWrapper<UserRole> wrapper = new LambdaQueryWrapper<>();

        wrapper.eq(UserRole::getUserId, userId);

        this.userRoleMapper.delete(wrapper);

        return ResponseResult.success();
    }

    @SneakyThrows(Exception.class)
    @Override
    public ResponseResult<Object> updateUser(MultipartHttpServletRequest request) {
        String userId = JwtUtils.parseForValue(request.getHeader("token"), "userId", String.class);
        User user = JSON.parseObject(request.getParameter("user"), User.class);
        if (Objects.equals(user.getUserName(), "admin")) {
            return ResponseResult.fail("无法更改超级管理员");
        }
        MultipartFile file = request.getFile("file");
        if (Objects.nonNull(file)) {
            if (StringUtils.hasText(user.getAvatar())) {
                try {
                    storageTemplate.deleteFile(user.getAvatar().replaceFirst("^.*//.*aliyuncs.com/", "").replaceFirst("\\?.*", ""));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            String url = storageTemplate.uploadFile(file.getBytes(), file.getOriginalFilename());
            user.setAvatar(url);
        }
        if (StringUtils.hasText(user.getPassword())) {
            user.setPassword(passwordEncoder.encode(user.getPassword()));
        }
        user.setUpdateBy(Long.valueOf(userId));
        user.setUpdateTime(new Date());
        this.baseMapper.updateById(user);
        return ResponseResult.success();
    }


    @SneakyThrows(Exception.class)
    @Override
    @CustomTransaction
    public ResponseResult<Object> addUser(MultipartHttpServletRequest request) {
        String userId = JwtUtils.parseForValue(request.getHeader("token"), "userId", String.class);
        User user = JSON.parseObject(request.getParameter("user"), User.class);
        MultipartFile file = request.getFile("file");
        if (Objects.nonNull(file)) {
            String url = storageTemplate.uploadFile(Objects.requireNonNull(file).getBytes(), file.getOriginalFilename());
            user.setAvatar(url);
        }
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        user.setCreateBy(Long.valueOf(userId));
        user.setUpdateBy(Long.valueOf(userId));
        Date date = new Date();
        user.setCreateTime(date);
        user.setUpdateTime(date);
        this.baseMapper.insertReturnUserId(user);

        UserRole userRole = new UserRole();
        userRole.setUserId(user.getUserId());
        userRole.setRoleId(2L);
        userRoleMapper.insert(userRole);

        return ResponseResult.success();
    }

    @CustomTransaction
    @Override
    public ResponseResult<Object> registerUser(RegisterDTO registerDTO) {
        String flagKey = registerDTO.getFlagKey();
        String code = flagKey != null ? (String) simpleCacheTemplate.get(flagKey) : null;
        if (code == null) {
            return ResponseResult.fail("验证码已过期");
        }
        if (!Objects.equals(registerDTO.getVerificationCode(), code)) {
            return ResponseResult.fail("验证码错误");
        }
        if (this.baseMapper.selectOneByUserName(registerDTO.getUserName()) != null) {
            return ResponseResult.fail("当前用户已存在，请更换用户名");
        }
        try {
            User user = new User();
            BeanUtils.copyProperties(registerDTO, user);
            user.setPassword(passwordEncoder.encode(registerDTO.getPassword()));
            Date date = new Date();
            user.setCreateTime(date);
            user.setUpdateTime(date);
            this.baseMapper.insertReturnUserId(user);
            user.setUpdateBy(user.getUserId());
            user.setCreateBy(user.getUserId());
            user.setStatus("0");
            this.baseMapper.updateById(user);

            UserRole userRole = new UserRole();
            userRole.setUserId(user.getUserId());
            userRole.setRoleId(2L);
            userRoleMapper.insert(userRole);

        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.fail("注册失败!");
        }
        return ResponseResult.success("注册成功!");
    }


    @Override
    @CustomTransaction
    public ResponseResult<Object> grantRole(RoleDto roleDto, String token) {
        User user = this.getById(roleDto.getUserId());
        if (Objects.equals(user.getUserName(), "admin")) {
            return ResponseResult.fail("无法更改超级管理员角色");
        }
        LambdaQueryWrapper<UserRole> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserRole::getUserId, roleDto.getUserId());
        this.userRoleMapper.delete(wrapper);
        List<Long> roleIdList = roleDto.getRoleIdList();
        for (Long roleId : roleIdList) {
            UserRole userRole = new UserRole();
            userRole.setRoleId(roleId);
            userRole.setUserId(roleDto.getUserId());
            this.userRoleMapper.insert(userRole);
        }
        return ResponseResult.success();
    }

    @Override
    public ResponseResult<Object> updatePassword(String srcPassword, String newPassword, String token) {
        String userId = JwtUtils.parseForValue(token, "userId", String.class);
        User user = this.getById(userId);
        if (passwordEncoder.matches(srcPassword, user.getPassword())) {
            user.setPassword(passwordEncoder.encode(newPassword));
            this.updateById(user);
            return ResponseResult.success("修改成功");
        }
        return ResponseResult.fail("原密码错误，请重新输入");
    }

    @Override
    public ResponseResult<Location> getIpLocation(HttpServletRequest request) {
        Map<String, String> information = IpUtils.parseIp(request);
        Location location = new Location();
        location.setCity(information.get("city"));
        location.setProvince(information.get("province"));
        return ResponseResult.success(location);
    }

    @Override
    public ResponseResult<VerificationCodeVo> getVerificationCode() {
        //定义图形验证码的长、宽、验证码字符数、干扰元素个数
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(70, 40, 4, 30);
        String key = UUIDUtils.generateUUID();
        String imageBase64Data = lineCaptcha.getImageBase64Data();
        String verificationCode = lineCaptcha.getCode();
        simpleCacheTemplate.set(key, verificationCode, TimeUnit.SECONDS, 30);
        VerificationCodeVo verificationCodeVo = new VerificationCodeVo();
        verificationCodeVo.setFlagKey(key);
        verificationCodeVo.setDataUrl(imageBase64Data);
        return ResponseResult.success(verificationCodeVo);
    }


}
